/*
 * Time    : 2021-09-03 08:59:12
 * Author  : Gray Snail
 * Version : 1.0
 * Contact : shtao2011@sina.com
 * License : Copyright (c) 2021 Gray Snail
 * Desc    : 画矩形框
 *
 * 操作说明:
 *
 *
 * 左击: 画框,右键可取消
 * 右击: 选中,选中的框会显示锚点
 *     在选中的框上按住左键拖动,修改框的位置
 *     鼠标移动到选中标注的锚点,修改框的位置和大小
 * 按下delete键,删除选中的框
 *
 * 双击: 修改属性
 *
 * 注意:
 *  1.

 */

import paper from 'paper'
import HandlePoint from './HandlePoint'
import { Cursor, RectCorsor, KeyCode, Style } from './const'
import { Annotation, AnnoType } from '../data/annotation'
import { BaseAnno, BaseTool } from './base'
import { checkEvent, drawAssistLine, removeAssistLine } from './utils'

const { Path } = paper

export class AnnoRect extends BaseAnno {
  constructor(from, to) {
    super()
    const rect = new Path.Rectangle(from, to)
    rect.markType = 'temp_rect'
    rect.strokeWidth = Style.LineWidth
    rect.strokeColor = 'yellow'
    rect.strokeScaling = false
    rect.selectedColor = 'red'

    const children = rect.segments.map((segment, index) => {
      return new HandlePoint({ segments: [segment.point], cursor: RectCorsor[index] })
    })
    this.addChild(rect)
    this.addChildren(children)
    this.rect = rect
    this.handlePoints = children
    this._closed = true
    // hit-test: fill
    this.fillColor = new paper.Color(1, 1, 1, 0.1)
    this.opacity = 1
  }

  get annoType() {
    return AnnoType.RECT
  }

  movePoint(point, newPoint) {
    this.rect.segments.forEach((element) => {
      if (element.point.x == point.x) {
        element.point.x = newPoint.x
      }
      if (element.point.y == point.y) {
        element.point.y = newPoint.y
      }
    })
    this.handlePoints.forEach((handlePt) => {
      if (handlePt.position.x == point.x) {
        handlePt.position.x = newPoint.x
      }
      if (handlePt.position.y == point.y) {
        handlePt.position.y = newPoint.y
      }
    })
    point.x = newPoint.x
    point.y = newPoint.y
    this.triggerEvnet()
  }

  get pts() {
    return [this.bounds.topLeft, this.bounds.bottomRight].map((pt) => ({ x: pt.x, y: pt.y }))
  }
}

const initialLocal = () => {
  return {
    from: null,
    rect: null,
    segment: null,
    assistLine: null,
    isDraged: false,
  }
}

let local

function onMouseMove(event) {
  if (!checkEvent(event)) return true
  event.tool.view.element.style.cursor = Cursor.Auto
  removeAssistLine(local)
  // console.log(`[x:${event.point.x}, y:${event.point.y}]`)

  const selectedItem = event.tool.selectedItem
  if (local.from) {
    local.rect?.remove()
    local.rect = event.tool.createItem(local.from, event.point)
    drawAssistLine(local, event.point, event.tool.imageSize)
    return true
  }

  if (selectedItem) {
    const layer = event.tool.layer
    layer.children.forEach((item) => item instanceof AnnoRect && (item.strokeWidth = Style.PointNormal))
    const hitResult = layer.hitTest(event.point, { segments: true, tolerance: 6, selected: true })
    const viewStyle = event.tool.view.element.style
    if (hitResult) {
      hitResult.item.strokeWidth = Style.PointExpand
      viewStyle.cursor = hitResult.item.cursor
      drawAssistLine(local, event.point, event.tool.imageSize)
    } else if (selectedItem.bounds.contains(event.point)) {
      removeAssistLine(local)
    } else {
      drawAssistLine(local, event.point, event.tool.imageSize)
    }
  } else {
    drawAssistLine(local, event.point, event.tool.imageSize)
  }
}

function onMouseDown(event) {
  const selectedItem = event.tool.selectedItem

  if (local.from) {
    return
  }
  const layer = event.tool.layer
  const hitResult = layer.hitTest(event.point, { segments: true, tolerance: 6, selected: true })
  // 左键选择 handlePoint, 右键选择 annoPath
  if (event.event.buttons === 1 && selectedItem) {
    if (hitResult) {
      const handlePoint = hitResult.item.segments[0].point
      local.segment = { x: handlePoint.x, y: handlePoint.y }
    }
  } else if (event.event.buttons === 2) {
    if (selectedItem && selectedItem.bounds.contains(event.point)) {
      // console.log(selectedItem)
      // do nothing
    } else {
      if (selectedItem) {
        selectedItem.selected = false
        event.tool.selectedItem = null
      }
      const hitResult = layer.hitTest(event.point, { fill: true, segments: true, stroke: true, class: AnnoRect })
      if (hitResult) {
        console.log(hitResult)
        hitResult.item.selected = true
        hitResult.item.fullySelected = true
        event.tool.selectedItem = hitResult.item
        removeAssistLine(local)
      }
    }
  }
}

function onMouseUp(event) {
  local.segment = null
  if (local.isDraged) {
    local.isDraged = false
    return true
  }
  const selectedItem = event.tool.selectedItem

  const project = event.tool.project
  const layer = project.activeLayer

  if (event.item === selectedItem) {
    // do nothing
    return
  }
  if (selectedItem) {
    console.log(event.item, selectedItem)
    selectedItem.selected = false
  }
  if (local.rect) {
    if (event.event.button === 0) {
      local.rect.selected = true
      const annotation = local.rect.createAnnotation()
      project?.updateProperty(annotation, (params) => {
        if (params) {
          event.tool.selectedItem = local.rect
        } else {
          local.rect.remove()
          event.tool.selectedItem = null
        }
        local.from = null
        local.rect = null
      })
    } else {
      local.rect.remove()
      local.from = null
      local.rect = null
      event.tool.selectedItem = null
    }
  } else if (!local.from) {
    if (event.event.button === 0) {
      local.from = event.point
      local.rect = null
    } else {
      local.from = null
      local.rect = null
    }
  }
}

function onMouseDrag(event) {
  local.isDraged = true
  removeAssistLine(local)
  const selectedItem = event.tool.selectedItem
  if (!selectedItem || event.event.buttons !== 1) return

  local.from = null
  if (local.segment) {
    selectedItem.movePoint(local.segment, event.point)
  } else if (event.item === selectedItem) {
    selectedItem.translate(event.delta)
  }
}

function onKeyDown(event) {
  const selectedItem = paper.project.selectedItem
  if (event.key === KeyCode.delete && selectedItem) {
    selectedItem.remove()
    paper.project.selectedItem = null
  }
}

function onActivate(lastTool) {
  local = initialLocal()
  const layerName = this.name + 'Layer'
  paper.projects.forEach((project) => {
    const layer = project.layers[layerName] || new paper.Layer({ name: layerName })
    project.addLayer(layer)
    layer.activate()
  })
}

function onDeactivate() {
  this.view.element.style.cursor = Cursor.Auto
  removeAssistLine(local)
  local.rect?.remove()
}

export default class RectTool extends BaseTool {
  constructor(options) {
    options.name = options.name || 'rect'
    super(options)
    this.onMouseDown = onMouseDown.bind(this)
    this.onMouseDrag = onMouseDrag.bind(this)
    this.onMouseUp = onMouseUp.bind(this)
    this.onMouseMove = onMouseMove.bind(this)
    this.onKeyDown = onKeyDown.bind(this)
    this.onActivate = onActivate.bind(this)
    this.onDeactivate = onDeactivate.bind(this)
  }

  static get meta() {
    return { icon: 'el-icon-crop', desc: '矩形框' }
  }

  get meta() {
    return { ...RectTool.meta, name: this.name }
  }

  // 创建 Annotation
  createItem(from, to) {
    return new AnnoRect(from, to)
  }
}
